home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / WAIS / ir / sersrch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-02  |  10.8 KB  |  380 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE
  2.    No guarantees or restrictions.  See the readme file for the full standard
  3.    disclaimer.    
  4.    Brewster@think.com
  5. */
  6.  
  7.  
  8. /* implements the search part of irext.h 
  9.    (search_word and finished_search_word)
  10.    -brewster
  11.  
  12. Split from irsearch.c
  13.  
  14.    5/31/91 Added scale_scores.  Fixed document_score_array to long.
  15.    7/8/91 Removed scale_scores, handled in search_word with doc_id > 0.
  16.  
  17.    - Jonny G
  18.  */
  19.  
  20. #include "cdialect.h"
  21. #include "irfiles.h"
  22. #include "irsearch.h"
  23. #include "irext.h"
  24. #include <string.h>
  25.  
  26. /*===========================*
  27.  *===  Setting Paramters  ===*
  28.  *===========================*/
  29.  
  30. long max_hit_retrieved = 0;
  31.  
  32. long set_query_parameter (mask, parameters)
  33.      long mask;
  34.      query_parameter_type * parameters;
  35. {
  36.   switch (mask)
  37.     {
  38.     case SET_MAX_RETRIEVED_MASK:
  39.       max_hit_retrieved = parameters->max_hit_retrieved;
  40.       break;
  41.     default:
  42.       break;
  43.     }
  44. }
  45.  
  46. /*==============================*
  47.  *===  Document Score Array  ===*
  48.  *==============================*/
  49.  
  50. long *document_score_array = NULL;
  51. long document_score_array_len = 0;
  52.  
  53. /* make_document_score_array insures that the document_score_array
  54.    array is long enough, if not it makes it long enough */
  55. static void make_document_score_array _AP((long length));
  56. static void make_document_score_array(length)
  57. long length;
  58. {
  59.   if(length <= document_score_array_len)
  60.     return;
  61.   /* we have to make a new one.  free the old one first (if any) */
  62.   if(document_score_array != 0){
  63.     s_free(document_score_array);
  64.   }
  65.   document_score_array = (long*)s_malloc(
  66.                      (size_t)(length * sizeof(long)));
  67.   document_score_array_len = length;
  68. }
  69.  
  70. static void destroy_document_score_array _AP((void));
  71. static void destroy_document_score_array()
  72. {
  73.   s_free(document_score_array);
  74.   document_score_array_len = 0;
  75. }
  76.     
  77. void clear_document_score_array()
  78. /* side effects the document_score_array.  XXX could use memset */
  79.   memset(document_score_array, 0, 
  80.      document_score_array_len * sizeof(long));
  81. }
  82.  
  83. /* for debugging purposes */
  84. void print_document_score_array(start,stop)
  85. unsigned long start;
  86. unsigned long stop;
  87. /* assumes start >= 0, stop < db->doc_table_allocated_entries */
  88. {
  89.     long i;
  90.     for(i = start; i <= stop; i++){
  91.         printf("entry number %d: %d \n", 
  92.                i, (unsigned char)document_score_array[i]);
  93.     }
  94. }
  95.  
  96.  
  97.  
  98. /*=========================*
  99.  *===  Best Hits Array  ===*
  100.  *=========================*/
  101.  
  102. hit *best_hits_array = NULL;
  103. long best_hits_array_len = 0;
  104. long current_best_hit = 0;
  105.  
  106. /* make_best_hits_array insures that the best_hits_array
  107.    array is long enough, if not it makes it long enough */
  108. static void make_best_hits_array _AP((long length));
  109. static void make_best_hits_array(length)
  110. long length;
  111. {
  112.   if(length <= best_hits_array_len)
  113.     return;
  114.   /* we have to make a new one.  free the old one first (if any) */
  115.   if(best_hits_array != 0){
  116.     s_free(best_hits_array);
  117.   }
  118.   best_hits_array = (hit*)s_malloc((size_t)(length * sizeof(hit)));
  119.   best_hits_array_len = length;
  120. }
  121.  
  122. static void destroy_best_hits_array _AP((void));
  123. static void destroy_best_hits_array()
  124. {
  125.   s_free(best_hits_array);
  126.   best_hits_array_len = 0;
  127. }
  128.     
  129. void clear_best_hits_array()
  130. /* side effects the best_hits_array.  XXX could use memset */
  131.   memset((char*)best_hits_array, 0, best_hits_array_len * sizeof(hit));
  132. }
  133.  
  134. /* for debugging purposes */
  135. void print_best_hits()
  136. {
  137.   long i;
  138.   for( i = 0; i < best_hits_array_len; i++){
  139.     if (best_hits_array[i].weight != 0)
  140.       { printf("Best hit %ld: weight %ld, doc_id %ld, headline %s, filename %s, lines %ld\n", 
  141.            i, best_hits_array[i].weight, 
  142.            best_hits_array[i].document_id,
  143.            best_hits_array[i].headline,
  144.            best_hits_array[i].filename,
  145.            best_hits_array[i].number_of_lines);
  146.       }
  147.   }
  148. }
  149.  
  150. void sort_best_hits(db)
  151.      database * db;
  152. {
  153.   /* returns nothing.
  154.    * side effects best_hits and document_score_array
  155.    */
  156.  
  157.   long i, doc;
  158.   long worst_weight_to_make_it = 0;
  159.   document_table_entry doc_entry;
  160.   long best_hit_number = 0;
  161.  
  162.   /* snuff the scores */
  163.   for(i = 0; i < max_hit_retrieved; i++){
  164.     best_hits_array[i].weight = 0;
  165.   }
  166.  
  167.   /* loop over the doc, and keep the doc_id and weight in best hit table */
  168.   for(doc = 0; doc < db->doc_table_allocated_entries; doc++){
  169.     long weight = document_score_array[doc];
  170.     if(worst_weight_to_make_it < weight){
  171.       /* merge it into the best_hits array. start at the bottom */
  172.       for(i = (max_hit_retrieved - 1); i >= 0; i--){
  173.     if(weight > best_hits_array[i].weight 
  174.        /* && (check_document_id(doc, db) == true) too slow.*/
  175.        ){
  176.       /* move this entry down */    
  177.       if((i + 1) < max_hit_retrieved){
  178.         best_hits_array[i+1].weight = best_hits_array[i].weight;
  179.         best_hits_array[i+1].document_id = best_hits_array[i].document_id;
  180.       }
  181.       best_hits_array[i].document_id = doc;
  182.         best_hits_array[i].weight = weight;
  183.     }
  184.     else
  185.       break;
  186.       }      
  187.     }
  188.   }
  189.   
  190.   for(i = 0; i < max_hit_retrieved; i++){
  191.     if(best_hits_array[i].weight <= 0)  /* if we are out of good stuff, return */
  192.       return;
  193.     /* fill in the rest of the hit */
  194.     if (read_document_table_entry(&doc_entry,
  195.                   best_hits_array[i].document_id,
  196.                   db) 
  197.     == true){
  198.       best_hits_array[best_hit_number].weight = best_hits_array[i].weight;
  199.       best_hits_array[best_hit_number].document_id = best_hits_array[i].document_id;
  200.       best_hits_array[best_hit_number].start_character = doc_entry.start_character;
  201.       best_hits_array[best_hit_number].end_character = doc_entry.end_character;
  202.       best_hits_array[best_hit_number].document_length = doc_entry.document_length;
  203.       best_hits_array[best_hit_number].number_of_lines = doc_entry.number_of_lines;
  204.       read_filename_table_entry(doc_entry.filename_id, 
  205.                 best_hits_array[best_hit_number].filename,
  206.                 best_hits_array[best_hit_number].type,
  207.                 NULL,
  208.                 db),
  209.       strncpy(best_hits_array[best_hit_number].headline, 
  210.           read_headline_table_entry(doc_entry.headline_id,db),
  211.           MAX_FILE_NAME_LEN);
  212.       best_hit_number++;
  213.     } 
  214.     beFriendly();
  215.   }
  216.   for(i = best_hit_number; i < max_hit_retrieved; i++){
  217.     best_hits_array[best_hit_number].weight = 0;
  218.   }
  219.   /* print_best_hits(s);  for debugging */
  220. }
  221.  
  222.  
  223. /* returns the next best hit */
  224. long best_hit(doc_id, score)
  225.      long *doc_id;    
  226.      long *score;
  227. {
  228.   if(current_best_hit > best_hits_array_len)
  229.     return(1);
  230.   if(best_hits_array[current_best_hit].weight == 0)
  231.     return(1);
  232.   *doc_id = best_hits_array[current_best_hit].document_id;
  233.   *score  = best_hits_array[current_best_hit].weight;
  234.   current_best_hit++;
  235.   return(0);
  236. }
  237.  
  238. long finished_best_hit()
  239. { /* if we are on a small machine, we might want to 
  240.      destroy_document_score_array */
  241.   clear_document_score_array();
  242.   clear_best_hits_array();
  243.   current_best_hit = 0;
  244.   return(0);
  245. }
  246.  
  247. /*=============================*    
  248.  *===  Searching for words  ===*
  249.  *=============================*/
  250.  
  251. long search_word(word,char_pos, line_pos, weight, doc_id, dictionary_value,
  252.          db)
  253.      char *word; /* the word to be searched for */
  254.      long char_pos;        /* the position of the start of the word */
  255.      long line_pos;        /* is this needed? not for signature system */
  256.      long weight;        /* how important the word looks syntactically,
  257.                    such as is it bold */
  258.      long doc_id;        /* current document, seed words is 0,
  259.                    then it increments into the relevant 
  260.                    document */
  261.      long dictionary_value;    /* this is from the disk dictionary,
  262.                    a signature system would use weight,
  263.                    inverted file systems would put
  264.                    position information */
  265.      database *db;
  266. {
  267.   /* this side effects the document_score_array,
  268.    * and downcases the word.
  269.    * Returns 0 if successful or word not present, 
  270.    * returns non-0 if an error.
  271.    *
  272.    */
  273.   
  274.   long not_full_flag = INDEX_BLOCK_FULL_FLAG; /*start out full so it will go on looking */
  275.   long count, index_block_size;
  276.   long internal_document_id, internal_weight, number_of_valid_entries;
  277.   long index_file_block_number = dictionary_value;
  278.   
  279.   FILE *stream = NULL;
  280.   current_best_hit = 0;  /* so that the best hits willstart from 0 */
  281.  
  282.   /* check the document_score_array */
  283.   if(document_score_array_len < db->doc_table_allocated_entries)
  284.     make_document_score_array(db->doc_table_allocated_entries);
  285.  
  286.   if(index_file_block_number >= 0){
  287.     stream = db->index_stream;
  288.     
  289.     while((not_full_flag != INDEX_BLOCK_NOT_FULL_FLAG) && 
  290.       (index_file_block_number != 0)){    
  291.       /* read the index block */
  292.       if (0 != fseek(stream, (long)index_file_block_number, 
  293.              SEEK_SET))    
  294.     { 
  295.       waislog(WLOG_HIGH, WLOG_ERROR, 
  296.           "fseek failed into the inverted file to position %ld",
  297.           (long)index_file_block_number); 
  298.       return(-1);
  299.     }
  300.       
  301.       not_full_flag = read_bytes(INDEX_BLOCK_FLAG_SIZE, stream);
  302.       index_file_block_number = read_bytes(NEXT_INDEX_BLOCK_SIZE, stream);
  303.       index_block_size = read_bytes(INDEX_BLOCK_SIZE_SIZE, stream);
  304.       if(EOF == index_block_size) 
  305.     { 
  306.       waislog(WLOG_HIGH, WLOG_ERROR, 
  307.           "reading from the index file failed");
  308.       return(-1);
  309.     }
  310.       
  311.       if(not_full_flag == INDEX_BLOCK_NOT_FULL_FLAG){
  312.     /* not full */
  313.     number_of_valid_entries = index_file_block_number;
  314.       }
  315.       else if(not_full_flag == INDEX_BLOCK_FULL_FLAG){
  316.     /* full */
  317.     number_of_valid_entries = index_block_size - INDEX_BLOCK_HEADER_SIZE;
  318.       }
  319.       else{            /* bad news, file is corrupted. */
  320.     waislog(WLOG_HIGH, WLOG_ERROR, 
  321.         "Expected the flag in the inverted file to be valid.  it is %ld",
  322.         not_full_flag);
  323.     return(-1);
  324.       }
  325.       /* printf("number of valid bytes: %ld\n", number_of_valid_entries); */
  326.       
  327.       /* add the array to the document_score_array */
  328.       for(count = 0; count < number_of_valid_entries; 
  329.       count = count + INDEX_ELEMENT_SIZE){
  330.     internal_document_id = read_bytes(DOCUMENT_ID_SIZE, stream);
  331.     (void)read_bytes(WORD_POSITION_SIZE, stream);
  332.     (void)read_bytes(CHARACTER_POSITION_SIZE, stream);
  333.     internal_weight = read_bytes(WEIGHT_SIZE,stream);
  334.     /* printf("entry %ld, Doc_id: %ld, weight %ld \n",
  335.         count, internal_document_id, internal_weight); */
  336.     if(EOF == internal_weight) 
  337.       { 
  338.         waislog(WLOG_HIGH, WLOG_ERROR, 
  339.             "reading from the doc-id table failed");
  340.         return(-1);
  341.       }
  342.     if(doc_id > 0) /* we are doing a relevant document */
  343.       internal_weight /= 0.1;
  344.  
  345.     document_score_array[internal_document_id] = 
  346.       document_score_array[internal_document_id] + internal_weight;
  347.       }
  348.     }
  349.     return(0); 
  350.   }
  351.   else if(0 == index_file_block_number){
  352.     /* an error occurred on looking up the word */
  353.     return(-1);
  354.   }
  355.   else                /* index_file_block_number is negative */
  356.     return(0);        /* word not present */
  357. }
  358.  
  359. /* now collect the best hits */
  360. long finished_search_word(db)
  361.      database *db;
  362.   /* check the document_score_array */
  363.   if(document_score_array_len < db->doc_table_allocated_entries)
  364.     make_document_score_array(db->doc_table_allocated_entries);
  365.  
  366.   make_best_hits_array(max_hit_retrieved);
  367.   sort_best_hits(db);
  368.   return(0);
  369. }
  370.  
  371.  
  372.  
  373.  
  374.  
  375.  
  376.  
  377.